////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_CONCURRENCY_CALL_ONCE_INL__
#define __WN_CONCURRENCY_CALL_ONCE_INL__

#include "WNCore/inc/WNPlatform.h"
#include "WNCore/inc/WNTypes.h"
#include "WNCore/inc/WNAssert.h"
#include "WNCore/inc/WNAtomic.h"
#include "WNConcurrency/inc/WNThread.h"

namespace WNConcurrency {
    WN_INLINE WN_VOID WNCallOnce(WN_ONCE_FLAG_T* _flag, WN_CALL_ONCE_FUNCTION_T _function) {
        while (WN_TRUE) {
            const WN_ATOM_T previous = WNAtomicCompareSwap(_flag, 1, 0);

            if (previous == 2) {
                return;
            } else if (previous == 0) {
                break;
            } else {
                WN_RELEASE_ASSERT(previous == 1);

                WNThreadYield();
            }
        }

        _function();

        WNAtomicSwap(_flag, 2);
    }
}

#endif // __WN_CONCURRENCY_CALL_ONCE_INL__